package cn.bearspark.tag.provider.dao.buffer;

import cn.bearspark.framework.redis.starter.buffer.hash.un.RedisHashBuffer;
import cn.bearspark.tag.provider.dao.co.TagCO;
import cn.bearspark.tag.provider.dao.repository.TagContentRepository;
import cn.bearspark.tag.provider.dao.key.TagBufferKeyBuilder;
import cn.bearspark.tag.provider.dao.mapper.TagBaseMapper;
import cn.bearspark.tag.provider.dao.po.TagIdContentPO;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 标签数据的 hash 缓存器
 *
 * @author f
 */
@Component
public class TagHashBuffer extends RedisHashBuffer<TagCO> {

    /**
     * 标签缓存的过期时间，默认为 5min
     */
    private static final int TAG_CACHE_EXPIRE = 60 * 5;

    /**
     * 标签内容的字段名
     */
    private final List<String> contentFieldNameList;

    private final TagContentRepository tagContentRepository;

    public TagHashBuffer(RedisTemplate<String, Object> redisTemplate,
                         TagBufferKeyBuilder tagBufferKeyBuilder,
                         TagBaseMapper tagBaseMapper,
                         TagContentRepository tagContentRepository) {
        super(
                redisTemplate,
                tagBufferKeyBuilder,
                TAG_CACHE_EXPIRE,
                TagCO.class,
                tagBaseMapper
        );
        this.tagContentRepository = tagContentRepository;

        // 加 viewNum 是为了防止查询缺失的热数据
        this.contentFieldNameList = List.of("content", "viewNum");
    }

    /**
     * 获取指定标签 id 集合对应的标签内容
     *
     * @param tagIdList 指定标签的 id 集合
     * @return 返回一个 Map，key：标签的 id，value：标签的内容
     */
    public Map<Long, String> mapContent(List<Long> tagIdList) {
        return super.mapLess(tagIdList, contentFieldNameList).entrySet().stream().collect(Collectors.toMap(
                Map.Entry::getKey,
                entry -> entry.getValue().getContent()
        ));
    }

    /**
     * 获取指定标签 id 对应的标签内容
     *
     * @param tagId 指定标签的 id
     * @return 指定标签 id 对应的标签内容
     */
    public String getContent(long tagId) {
        return super.getLess(tagId, contentFieldNameList).getContent();
    }

    /**
     * 将从 es 中查到的标签数据，映射成缓存对象
     *
     * @param tagIdContentPOList es 中查到的标签数据集合
     * @return 标签缓存对象集合
     */
    public List<TagCO> page(List<TagIdContentPO> tagIdContentPOList) {
        Map<Long, TagCO> tagCOMap = super.map(tagIdContentPOList.stream().map(TagIdContentPO::getTagId).toList());
        return tagIdContentPOList.stream().map(tagIdContentPO -> {
            TagCO tagCO = tagCOMap.get(tagIdContentPO.getTagId());
            String content = tagIdContentPO.getContent();
            if (StringUtils.hasText(content)) {
                tagCO.setContent(content);
            }
            return tagCO;
        }).toList();
    }

    /**
     * 查询指定的标签的缓存
     *
     * @param tagIdCollection 指定标签的 id 集合
     * @return 指定的标签的缓存集合
     */
    public List<TagCO> list(Collection<Long> tagIdCollection) {
        Map<Long, TagCO> tagCOMap = super.map(tagIdCollection);
        return tagIdCollection.stream()
                .map(tagCOMap::get)
                .toList();
    }

    /**
     * 从 es 中获取指定标签的内容
     *
     * @param tagCOIdList 指定标签的 id 集合
     * @return 指定标签的内容映射，key：标签的 id，value：标签的内容
     */
    @Override
    protected Map<Long, ?> mapExtraFromOtherDB(List<Long> tagCOIdList) {
        return tagContentRepository.mapContent(tagCOIdList);
    }

    /**
     * 将标签内容设置到标签的 co 对象中
     *
     * @param tagCO     指定的缓存
     * @param extraInfo 缓存的额外数据
     */
    @Override
    protected void setExtraInfo(TagCO tagCO, Object extraInfo) {
        tagCO.setContent((String) extraInfo);
    }
}
